<?php

namespace Xin\HttpClient;

use GuzzleHttp\Psr7\Utils;
use IteratorAggregate;
use Psr\Http\Message\StreamInterface;
use Traversable;
use Xin\Support\Str;

class SteamIterator implements IteratorAggregate
{
	/**
	 * @var StreamInterface
	 */
	protected $stream;

	/**
	 * @var bool
	 */
	protected $closed = false;

	/**
	 * @var callable
	 */
	protected $chunkResolver;
	/**
	 * @var callable
	 */
	protected $chunkCallback;

	/**
	 * SteamIterator constructor.
	 * @param StreamInterface $stream
	 */
	public function __construct(StreamInterface $stream)
	{
		$this->stream = $stream;
		// $this->closed = $this->stream->eof();
	}

	/**
	 * @return Traversable
	 */
	public function getIterator(): Traversable
	{
		$this->closed = false;

		while (!$this->isClosed() && !$this->stream->eof()) {
			$chunk = Utils::readLine($this->stream);
			if (trim($chunk) === "") {
				continue;
			}

			$chunk = $this->resolveChunk($chunk);

			$this->callChunkCallback($chunk);

			yield $chunk;
		}

		$this->close();
	}

	/**
	 * 关闭流
	 */
	public function close()
	{
		if (!$this->closed) {
			$this->closed = true;
		}
	}

	/**
	 * 是否关闭
	 * @return bool
	 */
	public function isClosed()
	{
		return $this->closed;
	}

	/**
	 * 解析数据
	 * @param string $chunk
	 * @return string
	 */
	protected function resolveChunk($chunk)
	{
		if ($this->chunkResolver) {
			$chunk = call_user_func($this->chunkResolver, $chunk);
		} else {
			$chunk = trim(Str::after($chunk, 'data:'));
		}

		return $chunk;
	}

	/**
	 * 设置解析器
	 * @param callable $chunkResolver
	 * @return $this
	 */
	public function setChunkResolver(callable $chunkResolver)
	{
		$this->chunkResolver = $chunkResolver;

		return $this;
	}

	/**
	 * 设置回调
	 * @param callable $chunkCallback
	 * @return void
	 */
	public function setOnChunk(callable $chunkCallback)
	{
		$this->chunkCallback = $chunkCallback;
	}

	/**
	 * 回调
	 * @param string $chunk
	 * @return void
	 */
	public function callChunkCallback(string $chunk)
	{
		if ($this->chunkCallback) {
			call_user_func($this->chunkCallback, $chunk);
		}
	}
}
